
// dma_minimal_fixed.c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
//#include "hisi_l0_mem_pool.h"
#include "hisi_l3t.h"

#define BUF_SIZE 2097152 * 2

static struct device *dev = NULL;
static void *cpu_addr = NULL;
static dma_addr_t dma_handle;

// 释放函数
static void dummy_device_release(struct device *dev)
{
    // 空函数，满足设备释放要求
    printk(KERN_INFO "DMA Test: Dummy device released\n");
}

// 创建一个完整的平台设备结构
static struct platform_device dummy_pdev = {
    .name = "dma_test_dummy",
    .id = -1,
    .dev = {
        .release = dummy_device_release,
    },
};

static int __init dma_minimal_init(void)
{
    int ret;

    printk(KERN_INFO "DMA Minimal Test: Starting\n");

    // 注册平台设备
    ret = platform_device_register(&dummy_pdev);
    if (ret) {
        printk(KERN_ERR "DMA Minimal Test: Failed to register platform device\n");
        return ret;
    }

    // 使用平台设备的设备结构
    dev = &dummy_pdev.dev;

    printk(KERN_INFO "DMA Minimal Test: Using device: %s\n", dev_name(dev));

    // 尝试设置DMA掩码
    ret = dma_set_mask(dev, DMA_BIT_MASK(32));
    if (ret) {
        printk(KERN_WARNING "DMA Minimal Test: Cannot set 32-bit DMA mask, error %d\n", ret);
    }

    // 尝试分配DMA内存
    printk(KERN_INFO "DMA Minimal Test: Attempting to allocate %d bytes\n", BUF_SIZE);

    cpu_addr = dma_alloc_coherent(dev, BUF_SIZE, &dma_handle, GFP_KERNEL);

    if (!cpu_addr) {
        printk(KERN_ERR "DMA Minimal Test: dma_alloc_coherent failed\n");

        // 尝试使用GFP_ATOMIC
        printk(KERN_INFO "DMA Minimal Test: Trying GFP_ATOMIC\n");
        cpu_addr = dma_alloc_coherent(dev, BUF_SIZE, &dma_handle, GFP_ATOMIC);
        if (!cpu_addr) {
            printk(KERN_ERR "DMA Minimal Test: GFP_ATOMIC also failed\n");
            platform_device_unregister(&dummy_pdev);
            return -ENOMEM;
        }
        printk(KERN_INFO "DMA Minimal Test: GFP_ATOMIC allocation succeeded\n");
    } else {
        printk(KERN_INFO "DMA Minimal Test: Allocation successful!\n");
        printk(KERN_INFO "DMA Minimal Test: CPU addr = %p, DMA handle = %pad\n",
               cpu_addr, &dma_handle);
    }

    ret = l3t_shared_lock(0, virt_to_pfn(cpu_addr), BUF_SIZE);
    if (ret)
    {
        pr_err("l0_dma_alloc_coherent: Failed to allocate  node %d, size=%zu\n",
               0, BUF_SIZE);
        dma_free_coherent(dev, BUF_SIZE, cpu_addr, dma_handle);
        return NULL;
    }

    // 测试内存访问
    if (cpu_addr) {
        memset(cpu_addr, 0x55, BUF_SIZE);
        printk(KERN_INFO "DMA Minimal Test: Memory write test completed\n");

        // 验证写入
        char *ptr = (char *)cpu_addr;
        int i;
        for (i = 0; i < 16; i++) {
            printk(KERN_INFO "DMA Minimal Test: buf[%d] = 0x%02x\n", i, ptr[i]);
        }
    }

    return 0;
}

static void __exit dma_minimal_exit(void)
{
    if (cpu_addr) {
        l3t_shared_unlock(0, virt_to_pfn(cpu_addr), BUF_SIZE);
        dma_free_coherent(dev, BUF_SIZE, cpu_addr, dma_handle);
        printk(KERN_INFO "DMA Minimal Test: Memory freed\n");
    }

    platform_device_unregister(&dummy_pdev);
    printk(KERN_INFO "DMA Minimal Test: Module unloaded\n");
}

module_init(dma_minimal_init);
module_exit(dma_minimal_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Test");
MODULE_DESCRIPTION("Minimal DMA test with fixed device release");
